package main

import (
	"log"
	"net/http"
	"os"
	"runtime"
	"strings"
)

const HTML_PATH = "./html"

func ErrPath(w http.ResponseWriter, r *http.Request) {
	http.Error(w, "403 Forbidden", http.StatusForbidden)
}

func viewHandle(w http.ResponseWriter, r *http.Request) {
	path := r.URL.Path
	// 限制非法路径访问
	if i := strings.Index(path, "../"); i != -1 {
		ErrPath(w, r)
		return
	}
	if path == "/" || path == "index.html" {
		path = "/index.html"
	}
	path = HTML_PATH + path
	log.Println(path)
	if exists := isExists(path); !exists {
		http.NotFound(w, r)
		return
	}
	http.ServeFile(w, r, path)
}

func isExists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	return os.IsExist(err)
}

func check(err error) {
	if err != nil {
		panic(err)
	}
}

func safeHandler(fn http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if e, ok := recover().(error); ok {
				http.Error(w, e.Error(), http.StatusInternalServerError)
				log.Println("WARN: panic in %v - %v", fn, e)
				//log.Println(string(debug.Stack()))
			}
		}()
		fn(w, r)
	}
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	http.HandleFunc("/", safeHandler(viewHandle))
	err := http.ListenAndServe(":80", nil)
	if err != nil {
		log.Fatal("ListenAndServer: ", err.Error())
	}
}
